package tam;

import static org.junit.Assert.assertTrue;
import robocode.control.events.BattleCompletedEvent;
import robocode.control.events.TurnEndedEvent;
import robocode.control.snapshot.BulletState;
import robocode.control.snapshot.IRobotSnapshot;
import robocode.control.testing.RobotTestBed;

/**
 * Behavioral test. Checks that Ringer only fires if in range, or if enemy
 * has run out of energy.
 *
 * @author Micah Takabayashi
 */
public class TestRingerFiring extends RobotTestBed {
  
  private boolean inRange = true;
  
  /**
   * Specifies that Corners and Ringer are to be matched up in this test case.
   *
   * @return The comma-delimited list of robots in this match.
   */
  @Override
  public String getRobotNames() {
    return "sample.Corners,tam.Ringer";
  }

  /**
   * This test runs for 10 rounds.
   *
   * @return The number of rounds.
   */
  @Override
  public int getNumRounds() {
    return 10;
  }

  /**
   * After each turn, checks if Ringer fired a shot when it shouldn't have.
   *
   * @param event Info about the current state of the battle.
   */
  @Override
  public void onTurnEnded(TurnEndedEvent event) {
    
    if (this.inRange) {
      
      // Finds distance between tanks.
      IRobotSnapshot enemy = event.getTurnSnapshot().getRobots()[0];
      IRobotSnapshot friend = event.getTurnSnapshot().getRobots()[1];
      double xDist = Math.abs(enemy.getX() - friend.getX());
      double yDist = Math.abs(enemy.getY() - friend.getY());
      double distance = Math.hypot(xDist, yDist);
      
      // If shot was fired by Ringer but tanks are farther than specified in Ringer or,
      // enemy is not depleted, set flag to false. Subs enemy velocity from distance
      // to account for possible lag between when enemy was detected and when shot was fired,
      // and enemy energy is offset by 9 to account for the possibility that Ringer was hit 
      // by an enemy shot while firing (causing them to regain health).
      for (int x = 0; x < event.getTurnSnapshot().getBullets().length; x++) {
        if ((event.getTurnSnapshot().getBullets()[x].getOwnerIndex() == 1) && 
          (event.getTurnSnapshot().getBullets()[x].getState() == BulletState.FIRED) &&
          distance - Math.abs(enemy.getVelocity()) > 200 &&
          enemy.getEnergy() > 9) {
            this.inRange = false;
        }
      }
    
    }
  }
  
  /**
   * After the battle, if Ringer fired a shot when it wasn't meant to, test fails.
   *
   * @param event Details about the completed battle.
   */
  @Override
  public void onBattleCompleted(BattleCompletedEvent event) {
    assertTrue("Check Enemy In Range", this.inRange);
  }
}